//
//  NSObject+HACInvocation.m
//  HACRouter
//
//  Created by Chengjie on 2019/5/2.
//

#import "NSObject+HACInvocation.h"

@implementation NSObject (HACInvocation)

- (id)hac_performInitSelector:(SEL)aSelector withArguments:(NSArray<NSString *>*)avgs {
    if (avgs && ![avgs isKindOfClass:[NSArray class]]) {
        return nil;
    }
    NSMethodSignature *signature = [[self class] instanceMethodSignatureForSelector:aSelector];
    if (!signature) { // 说明方法未找到
        return nil;
    }
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
    invocation.target = self;
    invocation.selector = aSelector;
    NSInteger count = MIN(avgs.count, signature.numberOfArguments - 2);
    for (NSInteger index = 0; index < count; index++) {
        const char *type = [signature getArgumentTypeAtIndex:index+2];
        if (!strcmp(type, "@")) {
            NSString *arg = avgs[index];
            if (![arg isKindOfClass:[NSString class]]) {
                continue;
            } else {
                [invocation setArgument:&arg atIndex:index+2];
            }
        } else if (!strcmp(type, @encode(NSInteger))) {
            NSInteger arg = [avgs[index] integerValue];
            [invocation setArgument:&arg atIndex:index+2];
        } else if (!strcmp(type, @encode(double))) {
            double arg = [avgs[index] doubleValue];
            [invocation setArgument:&arg atIndex:index+2];
        } else if (!strcmp(type, @encode(BOOL))) {
            BOOL arg = [avgs[index] boolValue];
            [invocation setArgument:&arg atIndex:index+2];
        } else if (!strcmp(type, @encode(int))) {
            int arg = [avgs[index] intValue];
            [invocation setArgument:&arg atIndex:index+2];
        } else if (!strcmp(type, @encode(float))) {
            float arg = [avgs[index] floatValue];
            [invocation setArgument:&arg atIndex:index+2];
        } else if (!strcmp(type, @encode(long long))) {
            long long arg = [avgs[index] longLongValue];
            [invocation setArgument:&arg atIndex:index+2];
        } else {
            continue;
        }
    }
    [invocation retainArguments];
    [invocation invoke];
    id __unsafe_unretained returnVal = nil;
    [invocation getReturnValue:&returnVal];
    return returnVal;
}


@end
